import json
from fastapi import HTTPException, Body

from middlewares.middlewares import generate_response

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import traceback
from typing import List
import asyncio
from concurrent.futures import ThreadPoolExecutor

from fastapi import Depends
from sqlalchemy.orm import Session

from routes.routers import v1_admin
from schemas.database import get_db
from schemas import crud, schemas
from logs.log import logger
from schemas.schemas import AdminEmail


def send_single_email(default_admin_email: AdminEmail, recipient_email: str, subject: str, message: str) -> bool:
    try:
        sender_email = default_admin_email.email
        print('recipient_email', recipient_email)
        msg = MIMEMultipart()
        msg['From'] = sender_email
        msg['To'] = recipient_email
        msg['Subject'] = subject
        msg.attach(MIMEText(message, 'plain'))

        with smtplib.SMTP(default_admin_email.smtp_server, default_admin_email.smtp_port) as smtp_connection:
            smtp_connection.starttls()
            smtp_connection.login(default_admin_email.username, default_admin_email.password)
            smtp_connection.send_message(msg)
        return True, "发送成功"
    except Exception as e:
        logger.error(f"发送邮件时出错: {str(traceback.format_exc())}")
        return False, f"发送邮件时出错: {str(e)}"

async def send_emails_with_thread_pool(default_admin_email: AdminEmail, recipient_emails: List[str], subject: str, message: str, db: Session, subscription: schemas.Subscription) -> List[dict]:
    results = []

    with ThreadPoolExecutor(max_workers=5) as executor:
        loop = asyncio.get_event_loop()
        tasks = []
        for recipient_email in recipient_emails:
            user = crud.get_user_by_email(db, recipient_email)
            if user and user.points >= subscription.points_cost:
                task = loop.run_in_executor(executor, send_single_email, default_admin_email, recipient_email, subject, message)
                tasks.append((recipient_email, task, True))
            else:
                insufficient_points_subject = "积分不足提醒"
                insufficient_points_message = f"尊敬的用户，您的积分不足以订阅此服务。当前积分：{user.points if user else 0}，所需积分：{subscription.points_cost}"
                task = loop.run_in_executor(executor, send_single_email, default_admin_email, recipient_email, insufficient_points_subject, insufficient_points_message)
                tasks.append((recipient_email, task, False))
        
        for recipient_email, task, has_enough_points in tasks:
            success, msg = await task
            
            email_log = schemas.EmailLogCreate(
                from_email=default_admin_email.email,
                to_email=recipient_email,
                subject=subject if has_enough_points else "积分不足提醒",
                content=message if has_enough_points else msg,
                status="成功" if success else "失败",
                error_message=msg
            )
            db_email_log = crud.create_email_log(db, email_log)
            
            if success and has_enough_points:
                user = crud.get_user_by_email(db, recipient_email)
                if user:
                    crud.create_point_log(db, user.id, -subscription.points_cost, "订阅扣除：%s" % subscription.name)
                    crud.update_user_points(db, user.id, -subscription.points_cost)
            
            results.append({
                "recipient": recipient_email,
                "success": success and has_enough_points,
                "message": msg if not has_enough_points else "邮件发送成功并扣除积分"
            })

    return results

@v1_admin.post("/test_admin_email/")
async def send_subscription_email(
    admin_email_id: int=Body("admin_email_id"),
    send_to: str=Body("send_to"),
    db: Session = Depends(get_db)
):
    try:
        default_admin_email = crud.get_admin_email_by_id(db, admin_email_id)
        if not default_admin_email:
            raise HTTPException(status_code=404, detail="未找到管理员邮箱")
        success, msg = send_single_email(default_admin_email, send_to, "测试邮件可用性", "测试内容发送")
        if not success:
            return generate_response({}, 500, msg)
        return generate_response({}, 200, msg)
    except Exception as e:
        logger.error(traceback.format_exc())
        return generate_response({}, 500, str(e))

@v1_admin.post("/send_email/", response_model=List[schemas.EmailLog])
async def send_subscription_email(
    subscription_id: int,
    content: str,
    db: Session = Depends(get_db)
):
    sender_email = crud.get_default_admin_email(db)
    if not sender_email:
        raise HTTPException(status_code=404, detail="未找到管理员邮箱")
    
    subscription = crud.get_subscription(db, subscription_id)
    if not subscription:
        raise HTTPException(status_code=404, detail="未找到指定的订阅")
    
    users = crud.get_users(db)
    recipient_emails = [user.emails[0].email for user in users if user.emails]
    
    message_template = subscription.message_template
    try:
        content = json.loads(content)
    except:
        return generate_response({}, 500, "content 必须为json")
    message = message_template.format(**content)
    
    results = await send_emails_with_thread_pool(sender_email, recipient_emails, subscription.email_subject, message, db, subscription)
    
    return generate_response(results, 200, "邮件发送完成")
